import {Axis, Direction, Point} from "../../../nodeApp/static/lib/crowncad-plugin-sdk-0.0.1";
import {Vector2} from "three";

class BeltDriveModelCommand{
  constructor() {
  }

  /*************************************************
   * 特征接口及特征命令Start
   * *************************************************/
  //通过featureId获取实体
  async getEntitiesByFeature(query, feature) {
    let res = await query.getEntitiesByFeatureIds([feature?.id]);
    let entities = res?.data?.entities;
    return entities?.length > 0 ? entities : null;
  }
  //通过featureId获取元素
  async getElementsByFeature(query, feature){
    let res = await query.getElementsByFeatureId(feature?.id);
    let elements = res?.data?.elements;
    return elements;
  }
  //距离创建基准面
  async creatLoftSketchDatum1(datum, dis) {
    if (datum) {
      let res = await datum.createPlaneByDistanceIncrement({
        planeId: 8,
        invertNormal: 0,
        paralDis: dis,
        reverse: 0,
      }, '');
      let currentFeature = res?.data?.modelData?.currentFeature;
      if (currentFeature && currentFeature.length > 0) {
        let feature = {
          id: currentFeature[0]?.id,
          name: currentFeature[0]?.name,
        }
        return feature;
      }
    }
  }
  //点位创建基准面
  async creatLoftSketchDatum2(datum, pointList) {
    if (datum) {
      // 绘制基本面
      let res = await datum.createPlaneByThreePointsIncrement({
        threePnts: pointList,
        invertNormal: 0,
      }, '');
      let currentFeature = res?.data?.modelData?.currentFeature;
      if (currentFeature && currentFeature.length > 0) {
        let feature = {
          id: currentFeature[0]?.id,
          name: currentFeature[0]?.name,
        }
        return feature;
      }
    }
  }
  //距离创建基准面
  async creatLoftSketchDatum3(datum, dis) {
    if (datum) {
      let res = await datum.createPlaneByDistanceIncrement({
        planeId: 22,
        invertNormal: 0,
        paralDis: dis,
        reverse: 0,
      }, '');
      let currentFeature = res?.data?.modelData?.currentFeature;
      if (currentFeature && currentFeature.length > 0) {
        let feature = {
          id: currentFeature[0]?.id,
          name: currentFeature[0]?.name,
        }
        return feature;
      }
    }
  }
  //拉伸凸台/基体
  async extrudeAddendum(query, solid, sketchFeature, extrudeType1, height1) {
    if (query && sketchFeature) {
      let entities = await this.getEntitiesByFeature(query, sketchFeature);
      if (entities && entities.length > 0) {
        let res = await solid.extrudeIncrement({
          sketch: entities[0]?.id,
          extrudeType1: extrudeType1,
          height1: height1 + '',
        }, '');
        let currentFeature = res?.data?.modelData?.currentFeature;
        if (currentFeature && currentFeature.length > 0) {
          let feature = {
            id: currentFeature[0]?.id,
            name: currentFeature[0]?.name,
          }
          return feature;
        }
      }
    }
  }
  //拉伸凸台/基体(沿指定方向)
  async extrudeWithDirectionAddendum(query, solid, sketchFeature, direction,extrudeType1, height1) {
    if (query && sketchFeature) {
      let entities = await this.getEntitiesByFeature(query, sketchFeature);
      if (entities && entities.length > 0) {
        let res = await solid.extrudeIncrement({
          sketch: entities[0]?.id,
          directionType: 1,
          direction: direction,
          extrudeType1: extrudeType1,
          height1: height1 + '',
        }, '');
        let currentFeature = res?.data?.modelData?.currentFeature;
        if (currentFeature && currentFeature.length > 0) {
          let feature = {
            id: currentFeature[0]?.id,
            name: currentFeature[0]?.name,
          }
          return feature;
        }
      }
    }
  }
  //旋转凸台/基体
  async revolveAddendum(query, solid, sketchFeature, beltDriveParams, reverse, angle1, no) {
    if (query && sketchFeature) {
      let axis = new Axis();
      if(no === 1) {
        axis.setPoint(new Point(0, 0, 0), new Point(0, 0, 1));
      } else if(no === 2) {
        axis.setPoint(new Point(parseFloat(beltDriveParams.distance), 0, 0), new Point(parseFloat(beltDriveParams.distance), 0, 1));
      }
      let entities = await this.getEntitiesByFeature(query, sketchFeature);
      if (entities && entities.length > 0) {
        let res = await solid.revolveIncrement({
          sketch: entities[0]?.id,
          axis: axis,
          reverse: reverse,
          revolveType1: 0,
          angle1: angle1,
          toSurface1: 0,
          revolveType2: -1,
        }, '');
        let currentFeature = res?.data?.modelData?.currentFeature;
        if (currentFeature && currentFeature.length > 0) {
          let feature = {
            id: currentFeature[0]?.id,
            name: currentFeature[0]?.name,
          }
          return feature;
        }
      }
    }
  }
  //拉伸切除
  async extrudeCutAddendum(query, solid, sketchFeature, extrudeFeature, reverse, extrudeType1, width) {
    if (!solid || !sketchFeature || !extrudeFeature) {
      return;
    }
    let sketchEntities = await this.getEntitiesByFeature(query, sketchFeature);
    if (sketchEntities && sketchEntities.length > 0) {
      let extrudeEntities = await this.getEntitiesByFeature(query, extrudeFeature);
      if (extrudeEntities && extrudeEntities.length > 0) {
        let res = await solid.extrudeCutIncrement({
          sketch: sketchEntities[0]?.id,
          reverse: reverse,
          extrudeType1: extrudeType1,
          height1: width,
          cutSolids: [extrudeEntities[0]?.id]
        }, '');
        let currentFeature = res?.data?.modelData?.currentFeature;
        if (currentFeature && currentFeature.length > 0) {
          let feature = {
            id: currentFeature[0]?.id,
            name: currentFeature[0]?.name,
          }
          return feature;
        }
      }
    }
  }
  //旋转切除
  async revolveCutAuxiliary(query, solid, sketchFeature, revolveCutFeature, beltDriveParams, axisX, axisY, reverse, angle1, no) {
    if (!solid || !sketchFeature || !revolveCutFeature) {
      return;
    }
    const axis = new Axis();
    if(no === 1) {
      axis.setPoint(new Point(axisX, axisY, 0), new Point(axisX, axisY, -1));
    } else if(no === 2) {
      axis.setPoint(new Point(parseFloat(beltDriveParams.distance) + axisX, axisY, 0), new Point(parseFloat(beltDriveParams.distance) + axisX, axisY, 1));
    }

    let sketchEntities = await this.getEntitiesByFeature(query, sketchFeature);
    if (sketchEntities && sketchEntities.length > 0) {
      let extrudeEntities = await this.getEntitiesByFeature(query, revolveCutFeature);
      if (extrudeEntities && extrudeEntities.length > 0) {
        let res = await solid.revolveCutIncrement({
          sketch: sketchEntities[0]?.id,
          axis: axis,
          reverse: reverse,
          revolveType1: 0,
          angle1: angle1,
          cutSolids: [extrudeEntities[0]?.id]
        }, '');
        let currentFeature = res?.data?.modelData?.currentFeature;
        if (currentFeature && currentFeature.length > 0) {
          let feature = {
            id: currentFeature[0]?.id,
            name: currentFeature[0]?.name,
          }
          return feature;
        }
      }
    }
  }
  //线性阵列(特征)
  async linearPatternFeatures(solid, cutFeature, beltDriveParams) {
    if (cutFeature) {
      let axis = new Direction();
      axis.setPoint(new Point(0, 0, 0), new Point(0, 0, 1));

      let res = await solid.linearPatternIncrement({
        baseType: 1,
        features: [cutFeature?.id],
        direction1: axis,
        spacing1: beltDriveParams.normalVWheel.e,
        instanceNum1: parseFloat(beltDriveParams.z) + '',
        geometryPattern: 0,
      }, '');
      let currentFeature = res?.data?.modelData?.currentFeature;
      if (currentFeature && currentFeature.length > 0) {
        let feature = {
          id: currentFeature[0]?.id,
          name: currentFeature[0]?.name,
        }
        return feature;
      }
    }
  }
  //线性阵列(实体)
  async linearPatternEntity(query, solid, cutFeature, beltDriveParams) {
    if (cutFeature) {
      let axis = new Direction();
      axis.setPoint(new Point(0, 0, 0), new Point(0, 0, 1));

      let entities = await this.getEntitiesByFeature(query, cutFeature);
      if (entities && entities.length > 0) {
        let entityId = entities[0]?.id;
        let res = await solid.linearPatternIncrement({
          baseType: 0,
          body: entityId,
          direction1: axis,
          spacing1: beltDriveParams.normalVWheel.e,
          instanceNum1: parseFloat(beltDriveParams.z) + '',
          geometryPattern: 0,
        }, '');
        let currentFeature = res?.data?.modelData?.currentFeature;
        if (currentFeature && currentFeature.length > 0) {
          let feature = {
            id: currentFeature[0]?.id,
            name: currentFeature[0]?.name,
          }
          return feature;
        }
      }
    }
  }
  //圆周阵列
  async circularPattern(solid, cutFeature, beltDriveParams, numHole, no) {
    if (cutFeature) {
      let axis = new Axis();
      if(no === 1) {
        axis.setPoint(new Point(0, 0, 0), new Point(0, 0, 1));
      } else if(no === 2) {
        axis.setPoint(new Point(parseFloat(beltDriveParams.distance), 0, 0), new Point(parseFloat(beltDriveParams.distance), 0, 1));
      }
      let res = await solid.circularPatternIncrement({
        baseType: 1,
        features: [cutFeature?.id],
        axis: axis,
        angle1: 360,
        instanceNum1: numHole,
      }, '');
      let currentFeature = res?.data?.modelData?.currentFeature;
      if (currentFeature && currentFeature.length > 0) {
        let feature = {
          id: currentFeature[0]?.id,
          name: currentFeature[0]?.name,
        }
        return feature;
      }
    }
  }
  /*************************************************
   * 特征接口及特征命令End
   * *************************************************/

  //共用接口
  //基准面
  async creatLoftSketchDatum(datum, pointList) {
    let sketchFeatures = []
    let datumFeatures1 = null;
    let datumFeatures2 = null;
    let datumFeatures3 = null;
    let datumFeatures4 = null;

    if(pointList.length > 0) {
      let pointFirst1 = new Point(pointList[0].inPoints[0].x, pointList[0].inPoints[0].y, 0);
      let pointFirst2 = new Point(pointList[0].outPoints[0].x, pointList[0].outPoints[0].y, 0);
      let pointFirst3 = new Point(pointList[0].inPoints[0].x, pointList[0].inPoints[0].y, 100);

      let pointSecond1 = new Point(pointList[0].inPoints[1].x, pointList[0].inPoints[1].y, 0);
      let pointSecond2 = new Point(pointList[0].outPoints[1].x, pointList[0].outPoints[1].y, 0);
      let pointSecond3 = new Point(pointList[0].inPoints[1].x, pointList[0].inPoints[1].y, 100);

      let pointThird1 = new Point(pointList[0].inPoints[2].x, pointList[0].inPoints[2].y, 0);
      let pointThird2 = new Point(pointList[0].outPoints[2].x, pointList[0].outPoints[2].y, 0);
      let pointThird3 = new Point(pointList[0].inPoints[2].x, pointList[0].inPoints[2].y, 100);

      let pointFourth1 = new Point(pointList[0].inPoints[3].x, pointList[0].inPoints[3].y, 0);
      let pointFourth2 = new Point(pointList[0].outPoints[3].x, pointList[0].outPoints[3].y, 0);
      let pointFourth3 = new Point(pointList[0].inPoints[3].x, pointList[0].inPoints[3].y, 100);

      let datumPointList1 = [];
      let datumPointList2 = [];
      let datumPointList3 = [];
      let datumPointList4 = [];

      datumPointList1.push(pointFirst1);
      datumPointList1.push(pointFirst2);
      datumPointList1.push(pointFirst3);
      datumPointList2.push(pointSecond1);
      datumPointList2.push(pointSecond2);
      datumPointList2.push(pointSecond3);
      datumPointList3.push(pointThird1);
      datumPointList3.push(pointThird2);
      datumPointList3.push(pointThird3);
      datumPointList4.push(pointFourth1);
      datumPointList4.push(pointFourth2);
      datumPointList4.push(pointFourth3);

      datumFeatures1 = await beltDriveModelCommand.creatLoftSketchDatum2(datum, datumPointList1);
      datumFeatures2 = await beltDriveModelCommand.creatLoftSketchDatum2(datum, datumPointList2);
      datumFeatures3 = await beltDriveModelCommand.creatLoftSketchDatum2(datum, datumPointList3);
      datumFeatures4 = await beltDriveModelCommand.creatLoftSketchDatum2(datum, datumPointList4);
      sketchFeatures.push(datumFeatures1);
      sketchFeatures.push(datumFeatures2);
      sketchFeatures.push(datumFeatures3);
      sketchFeatures.push(datumFeatures4);

      return sketchFeatures;
    }
  }
  /*************************************************
   * 几何计算Start
   * *************************************************/
  getBeltPoints(beltDriveParams, singleBeltThickness) {
    let radius1 = parseFloat(beltDriveParams.paramsWheel1.d) / 2;
    let radius2 = parseFloat(beltDriveParams.paramsWheel2.d) / 2;
    let distance = parseFloat(beltDriveParams.distance);
    let beltThickness = parseFloat(beltDriveParams.beltThickness);
    let beltCount = parseFloat(beltDriveParams.beltCount);
    let deep = 0;
    if(beltDriveParams.beltType === 'V') {
      let radian1 = (40 / 180) * Math.PI / 2;
      let diffX1 = (beltDriveParams.normalVBelt.b - beltDriveParams.normalVBelt.bp) / 2;
      let diffY1 = diffX1 / Math.tan(radian1);
      let wheelHa = beltDriveParams.normalVWheel.ha;

      let b = parseFloat(beltDriveParams.normalVBelt.b);
      let bd = parseFloat(beltDriveParams.normalVWheel.bd);
      let ha = parseFloat(beltDriveParams.normalVWheel.ha);
      let r1 = parseFloat(beltDriveParams.normalVWheel.r1);

      let radian = (beltDriveParams.normalVWheel.phi / 180) * Math.PI;  //32°
      let topX = ha * Math.tan(radian / 2);

      let angleA = 90 - (parseFloat(beltDriveParams.normalVWheel.phi) / 2); //74°
      let angleB = (180 - angleA) / 2; //53°
      let angleC = 90 - angleB; //37°
      let radianA = (angleA / 180) * Math.PI;
      let radianC = (angleC / 180) * Math.PI;

      //midLeft左移分量
      let r1X = r1 * Math.tan(radianC);

      let centerPointTop = new Point(0, 0, 0);
      let centerPointMid = new Point(centerPointTop.x, centerPointTop.y - ha, 0);

      let midLeft = new Point(centerPointMid.x - bd / 2, centerPointMid.y, 0);
      let midRight = new Point(centerPointMid.x + bd / 2, centerPointMid.y, 0);
      let topLeft = new Point(midLeft.x - topX, midLeft.y + ha, 0);
      let topRight = new Point(midRight.x + topX, midRight.y + ha, 0);

      let topLeftB = new Point(topLeft.x  + r1X * Math.cos(radianA), topLeft.y - r1X * Math.sin(radianA), 0);
      let topRightB = new Point(topRight.x  - r1X * Math.cos(radianA), topRight.y - r1X * Math.sin(radianA), 0);
      let arcDistance = Math.sqrt(Math.pow(topLeftB.x - topRightB.x, 2) + Math.pow(topLeftB.y - topRightB.y, 2));

      let diffLeftX = Math.abs(topRightB.y) * Math.tan(radian1);
      let beltAlignAtArcLength = b - 2 * diffLeftX;

      if(beltAlignAtArcLength >= arcDistance) {
        let diffX2 = (beltAlignAtArcLength - arcDistance) / 2;
        let diffY2 = diffX2 / Math.tan(radian1);

        deep = beltDriveParams.normalVBelt.h - diffY2;
      } else {
        let diffX2 = (b - arcDistance) / 2;
        let diffY2 = diffX2 / Math.tan(radian1);
        let diffY3 = r1X * Math.sin(radianA);

        deep = beltDriveParams.normalVBelt.h - diffY2 + diffY3;
      }
    }

    const circle1 = {
      x: 0,
      y: 0,
      radius: radius1
    };
    const circle2 = {
      x: distance,
      y: 0,
      radius: radius2
    };
    const points = this.calculateBeltPoints(circle1, circle2, beltCount, singleBeltThickness, deep);
    return {
      points: points.points,
      deep: deep,
      radian: points.radian
    };
  }
  calculateBeltPoints(circle1, circle2, beltCount, singleBeltThickness, deep) {
    // 获取圆心和半径
    const { x: x1, y: y1, radius: r1 } = circle1;
    const { x: x2, y: y2, radius: r2 } = circle2;

    const distance = Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
    const tangentLength = Math.sqrt(distance ** 2 - (r1 - r2) ** 2);
    const radian = Math.acos((r1 - r2) / distance);

    let cosValue = Math.cos(radian);
    let sinValue = Math.sin(radian);
    if(cosValue > -0.0001 && cosValue < 0.0001) {
      cosValue = 0;
    }
    if(sinValue > -0.0001 && sinValue < 0.0001) {
      sinValue = 0;
    }

    let points = [];
    for(let i = 0; i < beltCount; i++) {
      //内圈
      let inPoint1 = {
        x: x1 + (r1 + singleBeltThickness * i - deep) * cosValue,
        y: y1 + (r1 + singleBeltThickness * i - deep) * sinValue
      };
      let inPoint2 = {
        x: x1 + (r1 + singleBeltThickness * i - deep) * cosValue,
        y: y1 - (r1 + singleBeltThickness * i - deep) * sinValue
      };
      let inPoint3 = {
        x: x2 + (r2 + singleBeltThickness * i - deep) * cosValue,
        y: y2 + (r2 + singleBeltThickness * i - deep) * sinValue
      };
      let inPoint4 = {
        x: x2 + (r2 + singleBeltThickness * i - deep) * cosValue,
        y: y2 - (r2 + singleBeltThickness * i - deep) * sinValue
      };

      //外圈
      let outPoint1 = {
        x: x1 + (r1 + singleBeltThickness * (i + 1) - deep) * cosValue,
        y: y1 + (r1 + singleBeltThickness * (i + 1) - deep) * sinValue
      };
      let outPoint2 = {
        x: x1 + (r1 + singleBeltThickness * (i + 1) - deep) * cosValue,
        y: y1 - (r1 + singleBeltThickness * (i + 1) - deep) * sinValue
      };
      let outPoint3 = {
        x: x2 + (r2 + singleBeltThickness * (i + 1) - deep) * cosValue,
        y: y2 + (r2 + singleBeltThickness * (i + 1) - deep) * sinValue
      };
      let outPoint4 = {
        x: x2 + (r2 + singleBeltThickness * (i + 1) - deep) * cosValue,
        y: y2 - (r2 + singleBeltThickness * (i + 1) - deep) * sinValue
      };

      let point = {
        inPoints: [inPoint1, inPoint2, inPoint3, inPoint4],
        outPoints: [outPoint1, outPoint2, outPoint3, outPoint4],
      }
      points.push(point);
    }
    console.log('points: ' + points);
    // 返回切点和弧度
    return {
      points: points,
      radian: radian
    };
  }
  //计算两向量夹角
  calculateRadianBetweenTwoVectors(point1, point2, point3, point4) {
    let vector1 = new Vector2(point1.x - point2.x, point1.y - point2.y);
    let vector2 = new Vector2(point3.x - point4.x, point3.y - point4.y);

    const dot = vector1.x * vector2.x + vector1.y * vector2.y;

    let m1 = Math.sqrt(Math.pow(vector1.x, 2) + Math.pow((vector1.y), 2));
    let m2 = Math.sqrt(Math.pow(vector2.x, 2) + Math.pow((vector2.y), 2));

    let radian = Math.acos(dot / (m1 * m2));
    return radian;
  }

  //三点算圆心、半径、弧度
  calculateCenterRadiusRadian(point1, point2, point3) {
    let mx1 = (point1.x + point2.x) / 2;
    let my1 = (point1.y + point2.y) / 2;
    let mx2 = (point2.x + point3.x) / 2;
    let my2 = (point2.y + point3.y) / 2;

    let dx1 = point2.x - point1.x;
    let dy1 = point2.y - point1.y;
    let dx2 = point3.x - point2.x;
    let dy2 = point3.y - point2.y;

    let slope1 = -dx1 / dy1;
    let slope2 = -dx2 / dy2;

    let cx = (slope1 * mx1 - slope2 * mx2 + my2 - my1) / (slope1 - slope2);
    let cy = slope1 * (cx - mx1) + my1;

    let centerPoint = new Point(cx ,cy);
    let radius = Math.sqrt(Math.pow((cx - point1.x), 2) + Math.pow((cy - point1.y), 2));

    // let vector1 = new Vector2(point1.x - centerPoint.x, point1.y - centerPoint.y);
    // let vector2 = new Vector2(point3.x - centerPoint.x, point3.y - centerPoint.y);
    //
    // const dot = vector1.x * vector2.x + vector1.y * vector2.y;
    //
    // let m1 = Math.sqrt(Math.pow(vector1.x, 2) + Math.pow((vector1.y), 2));
    // let m2 = Math.sqrt(Math.pow(vector2.x, 2) + Math.pow((vector2.y), 2));
    //
    // let radian = Math.acos(dot / (m1 * m2));
    let radian = this.calculateRadianBetweenTwoVectors(point1, centerPoint, point3, centerPoint);

    return {
      centerPoint: centerPoint,
      radius: radius,
      radian: radian
    };
  }
  //计算交点
  calculateIntersection(point1, point2, point3, dis, isLeft) {
    let k = (point1.y - point2.y)/(point1.x - point2.x);
    let kb = point1.y - k * point1.x;

    let a = 1 + Math.pow(k, 2);
    let b = -2 * (point3.x + point3.y - k * kb);
    let c = Math.pow(point3.x, 2) + Math.pow(point3.y, 2) + Math.pow(kb, 2) - 2 * kb * point3.y - Math.pow(dis, 2);

    let delta = Math.pow(b, 2) - 4*a*c;
    if(delta >= 0) {
      if(isLeft) {
        let x1 = (-b - Math.sqrt(delta)) / (2 * a);
        let y1 = k * x1 + kb;
        let point = new Point(x1, y1);
        return point;
      } else {
        let x1 = (-b + Math.sqrt(delta)) / (2 * a);
        let y1 = k * x1 + kb;
        let point = new Point(x1, y1);
        return point;
      }
    } else {
      return null;
    }
  }
  /*************************************************
   * 几何计算End
   * *************************************************/
}

const beltDriveModelCommand = new BeltDriveModelCommand();
export {beltDriveModelCommand};
